	 PAGE	 ,132				; 					 ;AN000;
;	SCCSID = @(#)ifsdev.asm 1.0 87/05/11						 ;AN000;
TITLE	IFSFUNC DEVICE ROUTINES - Device/IOCTL routines 				 ;AN000;
NAME	IFSDEV										 ;AN000;
											 ;AN000;
;******************************************************************************
;
; Device related IFS calls
;
;   Printer_GetSet_String
;   IFS_Device_Check
;   IFS_Device_Close
;   IFS_Device_Oper
;   IFS_Spool_Echo_Check
;   IFS_DEPENDENT_IOCTL
;   DEVICE_IOCTL
;   GET_DFL_FROM_INDEX
;
; Programming notes:
;   Old redirector segmentation and DOS interface preserved.
;   Routine prologues are accurate for input/output.
;   However, the pseudocode was not kept up to date.
;   Use it for a rough idea of the routine function.
;
; REVISION HISTORY:
;	A000	Original version  4.00		  May 1987
;	A001	DCR 187 - ctrl req renumber, make attach type byte	  8/87 RGAZZIA
;	A002	PTM 764 - printer attach problems			  8/87 RGAZZIA
;	A003	PTM 849 - printer open	 problems			  8/87 RGAZZIA
;	A004	PTM 1244- Net Print	 problems			  8/87 RGAZZIA
;	A005	PTM 1600- dev ioctl ds bug				  8/87 RGAZZIA
;	A006	PTM 3619- thiscds,thissft not set in ifs dep ioctl	  2/88 RGazzia
;	A007	PTM 3971  Austin Print bug raid 			  3/88 RMG
;	A008	PTM 4055  UNC problems	(make sure thisdfl null on error) 3/30/88 RMG
;	A009	PTM 4188  Names=0 problems				  4/08/88 RMG
;	A010	PTM 4554  Echo across network in vitt alt task		  5/12/88 RMG
;	A011	PTM 4841  Ctrl ptrsc problems				  5/13/88 RMG
;	A012	PTM 4885  ifs dept ioctl not recog non-ifs drive	  5/17/88 RMG
;	A013	PTM 4791  problem with ax error code overwrite		  5/19/88 RMG
;	A014	PTM 4946  net - no ptrs 5E02 doesn't return error         5/20/88 RMG
;	A015	PTM 5005  get truncate flag faulty - ret on user stack	  6/02/88 RMG
;   LOC - 477
;
;******************************************************************************
											 ;AN000;
.xlist											 ;AN000;
.xcref											 ;AN000;
INCLUDE IFSSYM.INC									 ;AN000;
INCLUDE IFSFSYM.INC									 ;AN000;
INCLUDE DOSSYM.INC									 ;AN000;
INCLUDE DEVSYM.INC									 ;AN000;
.cref											 ;AN000;
.list											 ;AN000;
											 ;AN000;
AsmVars <IBM,KANJI,DEBUG>								 ;AN000;
											 ;AN000;
; define the base code segment of the network support first				 ;AN000;
											 ;AN000;
IFSSEG	SEGMENT BYTE PUBLIC 'IFSSEG'                                                     ;AN000;
IFSSEG	ENDS										 ;AN000;
											 ;AN000;
; include THE REST Of the segment definitions for normal MSDOS				 ;AN000;
											 ;AN000;
.xlist											 ;AN000;
include dosseg.asm									 ;AN000;
.list											 ;AN000;
											 ;AN000;
DATA		SEGMENT WORD PUBLIC 'DATA'                                               ;AN000;
	; DOSGROUP Data 								 ;AN000;
	Extrn	THISCDS:DWORD								 ;AN000;
	Extrn	THISSFT:DWORD								 ;AN000;
	Extrn	CDSAddr:DWORD								 ;AN000;
	Extrn	CDSCount:BYTE								 ;AN000;
	Extrn	CurrentPDB:WORD 							 ;AN000;
DATA		ENDS									 ;AN000;
											 ;AN000;
											 ;AN000;
IFSSEG	SEGMENT BYTE PUBLIC 'IFSSEG'                                                     ;AN000;
	ASSUME	SS:DOSGROUP,CS:IFSSEG							 ;AN000;
											 ;AN000;
	; IFS data									 ;AN000;
;;;aliasExtrn	NLAddr:DWORD								 ;AN000;
	Extrn	TEMPBUF:BYTE								 ;AN000;
	Extrn	UNC_FS_HDR:DWORD							 ;AN000;
	Extrn	THISIFS:DWORD								 ;AN000;
	Extrn	THISDFL:DWORD								 ;AN000;
	Extrn	DFLCount:BYTE								 ;AN000;
	Extrn	DFLAddr:DWORD								 ;AN000;
	Extrn	IFSDRV:BYTE								 ;AN000;
	Extrn	fAssign:BYTE								 ;AN000;
	Extrn	CDSAlt:DWORD								 ;AN000;
	Extrn	TRUNCATE_FLAG:BYTE							 ;AN000;
	Extrn	IFSPROC_FLAGS:WORD							 ;AN000;
	Extrn	IFSFUNC_FLAGS:WORD							 ;AN000;
	Extrn	IFSR:WORD								 ;AN000;
	Extrn	LPT1_NAME:BYTE								 ;AN000;
	Extrn	DEVICE_CB@_OFFSET:WORD							 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <PRINTER_GETSET_STRING Get/Set a Pre-pend string> 				 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; PRINTER_GETSET_STRING Get or Set the printer string and flag word			 ;AN000;
;											 ;AN000;
; Called by:  Dispatcher								 ;AN000;
;											 ;AN000;
; Routines called: CALL_IFS		DOS: Get_User_Stack				 ;AN000;
;		   GET_DFL_FROM_INDEX							 ;AN000;
;		   DF_TO_DFL								 ;AN000;
;											 ;AN000;
; Inputs:										 ;AN000;
;	AL has function type (2-printer-set 3-printer-get				 ;AN000;
;			     4-printer-set-flags 5-printer-get-flags			 ;AN000;
;		VALUE ALREADY RANGE CHECKED BY CALLER					 ;AN000;
;	DS:SI is user string pointer (call 2)						 ;AN000;
;	ES:DI is user buffer (call 3)							 ;AN000;
;	BX is assign index (calls 2,3,4,5)						 ;AN000;
;	CX is length DS:SI (call 2)							 ;AN000;
;	DX is flag word (call 4)							 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	Prep IFSRH:									 ;AN000;
;	*  IFSR_LENGTH	    DW	   48	    ; Request length				 ;AN000;
;	*  IFSR_FUNCTION    DB	    4	    ; Execute API function			 ;AN000;
;	   IFSR_RETCODE     DW	    ?							 ;AN000;
;	   IFSR_RETCLASS    DB	    ?							 ;AN000;
;	   IFSR_RESV1	    DB	   16 DUP(0)						 ;AN000;
;	*  IFSR_APIFUNC     DB	   16	    ; REDIR IOCTL (Printer Getset String)	 ;AN000;
;	   IFSR_ERROR_CLASS DB	    ?							 ;AN000;
;	   IFSR_ERROR_ACTION DB     ?							 ;AN000;
;	   IFSR_ERROR_LOCUS DB	    ?							 ;AN000;
;	   IFSR_ALLOWED     DB	    ?							 ;AN000;
;	   IFSR_I24_RETRY   DB	    ?							 ;AN000;
;	   IFSR_I24_RESP    DB	    ?							 ;AN000;
;	   IFSR_RESV2	    DB	    ?							 ;AN000;
;	*  IFSR_DEVICE_CB@  DD	    ?	    ; DFL entry found by IFSFUNC		 ;AN000;
;					    ; Step through CDS & DFL lists counting	 ;AN000;
;					    ; (0,1,2,...) ones with IFS bit set.	 ;AN000;
;					    ; Stop at BXth one.  Pass that in		 ;AN000;
;					    ; IFSR_DEVICE_CB@.				 ;AN000;
;	   IFSR_OPEN_CB@    DD	    ?							 ;AN000;
;	*  IFSR_FUNC	    DB	    0	    ; subfunction:				 ;AN000;
;					    ;	00 Generic IOCTL by device number	 ;AN000;
;	   IFSR_RESV3	    DB	    0							 ;AN000;
;	*  IFSR_BUFFER@     DD	    ?	    ; user buffer (see below)			 ;AN000;
;	*  IFSR_BUFSIZE     DW	    ?	    ; length					 ;AN000;
;	*  IFSR_CATEGORY    DB	    1	    ; category 1 for REDIR			 ;AN000;
;	*  IFSR_CTLFUNC     DB	    ?	    ; For AL=2,3 00F00001H F=0 GET,F=1 SET	 ;AN000;
;					    ;			   printer string	 ;AN000;
;					    ; For AL=4,5 00F00010H F=0 GET,F=1 SET	 ;AN000;
;					    ;			   printer flag 	 ;AN000;
;											 ;AN000;
;	   BUFFER	   LABEL   WORD     ; AL=2,3					 ;AN000;
;	   DATA 	   DB	   ...							 ;AN000;
;											 ;AN000;
;	   BUFFER	   LABEL   WORD     ; AL=4,5					 ;AN000;
;			   DW	   FLAGS    ; Printer mode flags			 ;AN000;
;					    ;  8000H=binary (vs.ascii)			 ;AN000;
;											 ;AN000;
;											 ;AN000;
;	CALL routine, CALL_IFS, with pointer to UNC capable IFS header			 ;AN000;
;	IF IFSR_RETCODE = 0 THEN							 ;AN000;
;	   DO										 ;AN000;
;	     IF AL=5 THEN DX = Flags							 ;AN000;
;	     Call DF_TO_DFL								 ;AN000;
;	   ENDDO									 ;AN000;
;	ELSE										 ;AN000;
;	   Set carry									 ;AN000;
;	   Put error code in AX 							 ;AN000;
;	ENDIF										 ;AN000;
;											 ;AN000;
;   Outputs:										 ;AN000;
;		If AL = 3 then CX bytes have been put at input ES:DI			 ;AN000;
;		If AL = 5 then DX is the flag word					 ;AN000;
;											 ;AN000;
;   Regs: nothing preserved								 ;AN000;
;											 ;AN000;
;   Notes:  This request is a REDIR.SYS dependent ioctl request 			 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure PRINTER_GETSET_STRING,NEAR						 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	TEST	CS:IFSFUNC_FLAGS,UNC_INSTALLED		; unc (redir.sys) must be	 ;AN000;
	JNZ	PGS_05					; installed, else do nothing	 ;AN000;
	MOV	AX,error_invalid_function						 ;AN000;
	transfer ifs_980								 ;AN000;
											 ;AN000;
PGS_05: 										 ;AN000;
	ifsr_fcn_def	EXECAPI 							 ;AN000;
	ifsr_api_def	DEPIOCTL							 ;AN000;
											 ;AN000;
	MOV	CS:DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@	; make sure this positioned	 ;AN000;
							; right 			 ;AN000;
	SaveReg <ES,AX> 				; preserve input es since	 ;AC007;
							; next call destroys it 	 ;AN000;
							; preserve ax too		 ;AN007;
	CALL	GET_DFL_FROM_INDEX			; sets [THISDFL],		 ;AN000;
							; ifsr_device_cb@ &		 ;AN000;
							; [THISIFS]			 ;AN000;
	JNC	PGS_10					; error on carry - no dfl	 ;AN000;
	ADD	SP,4					;   restore stack and		 ;AC007;
	transfer IFS_980				;   go return in ifsutil	 ;AC007;
											 ;AN000;
PGS_10: 										 ;AN000;
	RestoreReg <AX> 				; restore input al		 ;AN007;
	invoke	SET_DEPIOCTL_IFSR			; prep IFSRH			 ;AN000;
	MOV	ES:[BX.IFSR_CATEGORY],CATEGORY_REDIR					 ;AN000;
	CMP	AL,PRINTER_SET_STRING							 ;AN000;
	JNE	PGS_20									 ;AN000;
							; printer set string		 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],SI	;				 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],DS	;				 ;AN000;
	MOV	ES:[BX.IFSR_BUFSIZE],CX 		;				 ;AN000;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_PRINTER_SET_STRING 			 ;AN000;
	ADD	SP,2					; restore stack (es) &		 ;AN000;
	JMP	SHORT PGS_100				; go call redir.sys		 ;AN000;
											 ;AN000;
PGS_20: 										 ;AN000;
	CMP	AL,PRINTER_GET_STRING			; printer get string		 ;AN000;
	JNE	PGS_40									 ;AN000;
	POP	CX					; retrieve es in cx		 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],DI	;				 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],CX					 ;AN000;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_PRINTER_GET_STRING 			 ;AN000;
	JMP	SHORT PGS_100								 ;AN000;
											 ;AN000;
PGS_40: 						; flags 			 ;AN000;
	ADD	SP,2					; 1st clean stack of es 	 ;AN000;
	PUSH	CS					;   not needed here		 ;AN000;
	POP	DS					; must set up buffer		 ;AN000;
ASSUME	DS:IFSSEG					; to hold flag word		 ;AN000;
	MOV	SI,OFFSET TEMPBUF							 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],SI					 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],DS					 ;AN000;
	CMP	AL,PRINTER_SET_FLAGS							 ;AN000;
	JNE	PGS_60									 ;AN000;
	MOV	DS:[SI],DX				; printer set flags		 ;AN000;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_PRINTER_SET_FLAGS				 ;AN000;
	JMP	PGS_100 								 ;AN000;
											 ;AN000;
PGS_60: 						; printer get flags		 ;AN000;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_PRINTER_GET_FLAGS				 ;AN000;
											 ;AN000;
PGS_100:										 ;AN000;
	PUSH	AX					; save function 		 ;AN000;
											 ;AN000;
	PUSH	CS									 ;AN000;
	POP	DS									 ;AN000;
ASSUME	DS:IFSSEG									 ;AN000;
											 ;AN000;
	invoke	SET_THISIFS_UNC 			; set thisifs to unc		 ;AN000;
											 ;AN000;
	invoke	CALL_IFS				; call ifs driver w/request	 ;AN000;
											 ;AN000;
	JNC	PGS_120 								 ;AN000;
	ADD	SP,2					; clean stack of ax (fcn #)	 ;AN013;
	transfer ifs_980				;  go ret on error		 ;AN000;
											 ;AN000;
PGS_120:										 ;AN000;
	POP	AX					; restore original input fcn	 ;AN000;;AM013;
	invoke	DF_TO_DFL				; Update dfl entry		 ;AN000;
											 ;AN000;
	CMP	AL,PRINTER_GET_FLAGS			; if printer get flags		 ;AN000;
	JE	PGS_140 				;    put flags in DX		 ;AN000;
	CMP	AL,PRINTER_GET_STRING			; if printer get string 	 ;AN000;
	JE	PGS_160 				;    put stg size in CX 	 ;AN000;
											 ;AN000;
	transfer ifs_990								 ;AN000;
PGS_140:										 ;AN000;
	LES	DI,ES:[BX.IFSR_BUFFER@] 						 ;AN000;
	MOV	DX,WORD PTR ES:[DI]							 ;AC004;
	CallInstall Get_User_Stack,multDOS,24						 ;AN000;
	MOV	[SI].User_DX,DX 			; return user flags to dos	 ;AN000;
	transfer ifs_990				; go return with no carry	 ;AN000;
											 ;AN000;
PGS_160:										 ;AN000;
	MOV	CX,ES:[BX.IFSR_BUFSIZE] 						 ;AN000;
	CallInstall Get_User_Stack,multDOS,24						 ;AN000;
	MOV	[SI].User_CX,CX 	; Size of pre string just transferred		 ;AN000;
	transfer ifs_990				; go return with no carry	 ;AN000;
											 ;AN000;
EndProc PRINTER_GETSET_STRING								 ;AN000;
											 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <IFS_DEVICE_CHECK  See if given path is device>					 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; IFS_DEVICE_CHECK									 ;AN000;
;											 ;AN000;
; Called by:  Dispatcher								 ;AN000;
;											 ;AN000;
; Routines called: DFL_MATCH		DOS: PathChrCmp 				 ;AN000;
;		   DFL_TO_DF		     StrCpy					 ;AN000;
;		   CALL_IFS								 ;AN000;
; Inputs:										 ;AN000;
;	DS:SI -> name									 ;AN000;
;	ES:DI -> buffer 								 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	Search DFL for match on name.							 ;AN000;
;	IF match found THEN								 ;AN000;
;	   DO  /* match found */							 ;AN000;
;	     IF DFL_TYPE = 3 (net device) THEN						 ;AN000;
;		ES:DI -> parms								 ;AN000;
;	     Clear carry								 ;AN000;
;	   ENDDO									 ;AN000;
;	ELSE   /* no match found */							 ;AN000;
;	   Set carry									 ;AN000;
;	ENDIF										 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	no match:  carry set								 ;AN000;
;	match:	   carry clear,  es:di -> parms if unc					 ;AN000;
;											 ;AN000;
;											 ;AN000;
;   Regs: nothing preserved								 ;AN000;
;											 ;AN000;
; Programming notes:  Most of this code lifted right out of the Redirector.		 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure IFS_DEVICE_CHECK,NEAR 						 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	ifsr_fcn_def	ATTSTAT 							 ;AN000;
											 ;AN000;
	LocalVar    Src,DWORD				; ** netprn parse code begins	 ;AN000;
	LocalVar    Dst,DWORD								 ;AN000;
	LocalVar    DotPos,WORD 							 ;AN000;
	Enter										 ;AN000;
;											 ;AN000;
; Preserve all of the input quantities							 ;AN000;
;											 ;AN000;
	MOV	SrcL,SI 								 ;AN000;
	MOV	SrcH,DS 								 ;AN000;
	MOV	DstL,DI 								 ;AN000;
	MOV	DstH,ES 								 ;AN000;
	MOV	DotPos,-1								 ;AN000;
;											 ;AN000;
; Check for a UNC string. If UNC, is not spooled.					 ;AN000;
;											 ;AN000;
	MOV	AX,[SI] 								 ;AN000;
	CallInstall PathChrCmp,multDOS,4,<AX>,<AX>					 ;AN000;
	JNZ	NOT_UNC 								 ;AN000;
	XCHG	AH,AL									 ;AN000;
	CallInstall PathChrCmp,multDOS,4,<AX>,<AX>					 ;AN000;
	JZ	NOTSpool								 ;AN000;
NOT_UNC:										 ;AN000;
;											 ;AN000;
; Scan string remembering previous path separator char. 				 ;AN000;
;											 ;AN000;
	MOV	DI,SI			; remember first character			 ;AN000;
PathSkip:										 ;AN000;
	LODSB										 ;AN000;
	OR	AL,AL									 ;AN000;
	JZ	FoundEnd								 ;AN000;
IF Kanji										 ;AN000;
 kanji load of next char too								 ;AN000;
ENDIF											 ;AN000;
	CallInstall PathChrCmp,multDOS,4,<AX>,<AX>					 ;AN000;
	JZ	SaveSI									 ;AN000;
	CMP	AL,':'                                                                   ;AN000;
	JNZ	TestDot 								 ;AN000;
SaveSI: 										 ;AN000;
	MOV	DI,SI									 ;AN000;
	JMP	PathSkip								 ;AN000;
TestDot:										 ;AN000;
	CMP	AL,'.'                                                                   ;AN000;
	JNZ	PathSkip								 ;AN000;
	MOV	DotPos,SI								 ;AN000;
	JMP	PathSkip								 ;AN000;
											 ;AN000;
;											 ;AN000;
; Better check for trailing :.	They are ILLEGAL (read this comment, IBM) in		 ;AN000;
;  file names.										 ;AN000;
;											 ;AN000;
FoundEnd:										 ;AN000;
	CMP	BYTE PTR [SI-2],':'                                                      ;AN000;
	JNZ	NOCOL									 ;AN000;
NotSpool:										 ;AN000;
	SaveReg <AX,CS> 								 ;AN008;
	RestoreReg <DS> 								 ;AN008;
	MOV	AX,NULL_PTR								 ;AN008;
	MOV	WORD PTR [THISDFL],AX							 ;AN008;
	MOV	WORD PTR [THISDFL+2],AX 						 ;AN008;
	RestoreReg <AX> 								 ;AN008;
	LDS	SI,Src									 ;AN000;
	STC										 ;AN000;
Done:											 ;AN000;
	LES	DI,Dst									 ;AN000;
	Leave										 ;AN000;
	return										 ;AN000;
											 ;AN000;
NotSpoolLv:										 ;AN000;
	LeaveCrit   critNet								 ;AN000;
	JMP	NotSpool								 ;AN000;
											 ;AN000;
NOCOL:											 ;AN000;
	XCHG	SI,DI									 ;AN000;
;											 ;AN000;
; DS:SI points to remainder of string.	DS:DI points to 1 past NUL.  AL = 0		 ;AN000;
;											 ;AN000;
	CMP	DotPos,-1								 ;AN000;
	JZ	GetP									 ;AN000;
	MOV	DI,DotPos								 ;AN000;
	XCHG	AL,[DI-1]								 ;AN000;
;											 ;AN000;
; DI points to 1 past either former . (now NUL) or terminating NUL.  AL has		 ;AN000;
; former character (. or NUL)								 ;AN000;
;											 ;AN000;
						; ** end of netprn code 		 ;AN000;
GETP:						; ds:si -> parsed string		 ;AN000;
	invoke	DFL_MATCH								 ;AN000;
	MOV	ES,SrcH 								 ;AN000;
	MOV	ES:[DI-1],AL			; replace original character		 ;AN000;
	JNC	IDC_100 			; not in dfl; set bl=ff 		 ;AN000;
	JMP	NotSpool								 ;AN000;
											 ;AN000;
IDC_100:					; match found				 ;AN000;
	LES	DI,[THISDFL]								 ;AN000;
	CMP	ES:[DI.DFL_TYPE],TYPE_NET_DEVICE					 ;AN000;
	JE	IDC_120 								 ;AN000;
	LES	DI,Dst									 ;AN000;
	JMP	IDC_220 								 ;AN000;
											 ;AN000;
IDC_120:					; ifs: get parms			 ;AN000;
	invoke	PREP_IFSR			; clear ifsr				 ;AN003;
	MOV	CS:DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@					 ;AN003;
	invoke	DFL_TO_DF			; DFL: sets [THISIFS]			 ;AN000;
						;	    ES:BX -> IFSRH		 ;AN000;
						;	    IFSR_DEVICE_CB@		 ;AN000;
						;	    ds - IFSSEG 		 ;AN000;
	MOV	ES:[BX.IFSR_LENGTH],LENGTH_ATTSTAT					 ;AN000;
	MOV	ES:[BX.IFSR_FUNCTION],IFSATTSTAT					 ;AN000;
	invoke	SET_CATEGORY			; this has nothing to do w/catrgory	 ;AN000;
						; want to determine if unc or not	 ;AN000;
	OR     CL,CL				; unc cl=1, other cl=0			 ;AN000;
	JNE	IDC_140 								 ;AN000;
	MOV	ES:[BX.IFSR_TYPE],TYPE_DEVICE						 ;AN000;
	JMP	SHORT IDC_160								 ;AN000;
IDC_140:										 ;AN000;
	MOV	ES:[BX.IFSR_TYPE],TYPE_NET_DEVICE					 ;AN000;
IDC_160:										 ;AN000;
	PUSH	CS									 ;AN000;
	POP	DS									 ;AN000;
ASSUME	DS:IFSSEG									 ;AN000;
	MOV	SI,OFFSET TEMPBUF							 ;AN000;
	MOV	WORD PTR ES:[BX.IFSR_PARMS@],SI 					 ;AN000;
	MOV	WORD PTR ES:[BX.IFSR_PARMS@+2],DS					 ;AN000;
											 ;AN000;
	invoke	CALL_IFS								 ;AN000;
	JNC	IDC_200 								 ;AN008;
	JMP	NotSpool								 ;AC008;
											 ;AN000;
IDC_200:										 ;AN000;
	MOV	SI,ES:WORD PTR [BX.IFSR_PARMS@] 					 ;AN000;
	MOV	DS,ES:WORD PTR [BX.IFSR_PARMS@+2]					 ;AN000;
	MOV	BL,ES:[BX.IFSR_TYPE]							 ;AC001;
	XOR	BH,BH									 ;AN001;
	INC	SI				; ds:si -> parms returned by redir	 ;AN000;
	INC	SI									 ;AN000;
	LES	DI,Dst									 ;AN000;
	CallInstall StrCpy,multDOS,17							 ;AN000;
	DEC	DI				; now append device name to net path	 ;AN003;
	MOV	AL,'\'                          ;     |                                  ;AN003;
	STOSB					;     | 				 ;AN003;
	LDS	SI,CS:[THISDFL] 		;     | 				 ;AN003;
	ADD	SI,2				;     | 				 ;AN003;
	invoke	CONVERT_NAME_ASCIIZ		;     | mov name string over		 ;AN003;

IDC_220:										 ;AN000;
	LDS	SI,Dst									 ;AN000;
	CLC										 ;AN000;
	JMP	DONE									 ;AN000;
											 ;AN000;
											 ;AN000;
EndProc IFS_DEVICE_CHECK								 ;AN000;
											 ;AN000;
											 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <IFS_DEVICE_CLOSE  Do a close on a device session directly>			 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; IFS_DEVICE_CLOSE									 ;AN000;
;											 ;AN000;
; Called by:  IFSFUNC Dispatcher							 ;AN000;
;											 ;AN000;
; Routines called:									 ;AN000;
;		     SFT_TO_SFF 							 ;AN000;
;		     SFF_TO_SFT 							 ;AN000;
;		     CALL_IFS								 ;AN000;
;											 ;AN000;
; Inputs:  ES:DI -> SFT 								 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	Send request below to IFS specified if SFT.					 ;AN000;
;											 ;AN000;
;	Prep IFSRH:									 ;AN000;
;	*  IFSR_LENGTH	    DW	   48	    ; Request length				 ;AN000;
;	*  IFSR_FUNCTION    DB	    4	    ; Execute API function			 ;AN000;
;	   IFSR_RETCODE     DW	    ?							 ;AN000;
;	   IFSR_RETCLASS    DB	    ?							 ;AN000;
;	   IFSR_RESV1	    DB	   16 DUP(0)						 ;AN000;
;	*  IFSR_APIFUNC     DB	   16	    ; IFS dependent IOCTL			 ;AN000;
;	   IFSR_ERROR_CLASS DB	    ?							 ;AN000;
;	   IFSR_ERROR_ACTION DB     ?							 ;AN000;
;	   IFSR_ERROR_LOCUS DB	    ?							 ;AN000;
;	   IFSR_ALLOWED     DB	    ?							 ;AN000;
;	   IFSR_I24_RETRY   DB	    ?							 ;AN000;
;	   IFSR_I24_RESP    DB	    ?							 ;AN000;
;	   IFSR_RESV2	    DB	    ?							 ;AN000;
;	*  IFSR_DEVICE_CB@  DD	    ?	    ; DF					 ;AN000;
;	*  IFSR_OPEN_CB@    DD	    ?	    ; SF					 ;AN000;
;	*  IFSR_FUNC	    DB	    0	    ; generic IOCTL by handle			 ;AN000;
;	   IFSR_RESV3	    DB	    0							 ;AN000;
;	   IFSR_BUFFER@     DD	    ?							 ;AN000;
;	   IFSR_BUFSIZE     DW	    ?							 ;AN000;
;	   IFSR_CATEGORY    DB	    1 for UNC, 0 for all other FSs			 ;AN000;
;	   IFSR_CTLFUNC     DB	    00000101B ; device spool close			 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	Carry set   - error code in AX							 ;AN000;
;											 ;AN000;
;											 ;AN000;
; Regs: nothing preserved								 ;AN000;
;											 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure IFS_DEVICE_CLOSE,NEAR 						 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	ifsr_fcn_def	EXECAPI 							 ;AN000;
	ifsr_api_def	DEPIOCTL							 ;AN000;
											 ;AN000;
	SaveReg <DS,SI,ES,DI>			; preserve these for dos - guesing	 ;AN011;
	MOV	CS:DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@					 ;AN002;
	MOV	CS:IFSPROC_FLAGS,SETDEVICECB	; init processing flags 		 ;AN000;
											 ;AN000;
	Context DS									 ;AN000;
	MOV	WORD PTR [THISSFT],DI							 ;AN000;
	MOV	WORD PTR [THISSFT+2],ES 						 ;AN000;

	invoke	PREP_IFSR			;  &  ifsr				 ;AM011;
	invoke	SFT_TO_SFF			; sets [THISIFS]			 ;AN000;
						;      ES:BX -> IFSRH			 ;AN000;
						;      IFSR_OPEN_CB@			 ;AN000;
						;      IFSR_DEVICE_CB@			 ;AN000;
						;      ds - IFSSEG			 ;AN000;
	invoke	SET_DEPIOCTL_IFSR		; prep IFSRH				 ;AN000;
;;;;;;;;INC	ES:[BX.IFSR_FUNC]		; inc func from gen_ioctl_by_devnum	 ;AD011;
;;;;;;;;					; to gen_ioctl_by_handle		 ;AD011;
	invoke	SET_CATEGORY								 ;AN000;
	MOV	ES:[BX.IFSR_CATEGORY],CL						 ;AN002;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_DEVCLOSE					 ;AN000;
											 ;AN000;
	invoke	CALL_IFS			; call ifs w/device close request	 ;AN000;
											 ;AN000;
	JNC	IDCL_60 								 ;AN000;
	JMP	IDCL_1000			; go ret w/carry already set		 ;AC011;
											 ;AN000;
IDCL_60:										 ;AN000;
	invoke	SFF_TO_SFT								 ;AN000;
;;;;;;;;transfer ifs_990								 ;AD011;
IDCL_1000:										 ;AN011;
	RestoreReg <DI,ES,SI,DS>							 ;AN011;
	XOR	CX,CX				; set zero flag 			 ;AN011;;AC013;
	return										 ;AN011;
											 ;AN000;
											 ;AN000;
EndProc IFS_DEVICE_CLOSE								 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <IFS_DEVICE_OPER	 Do various device control functions>				 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; IFS_DEVICE_OPER									 ;AN000;
;											 ;AN000;
; Called by:  IFSFUNC Dispatcher							 ;AN000;
;											 ;AN000;
; Routines called:   PREP_IFSR								 ;AN000;
;		     CALL_IFS								 ;AN000;
;		     DFL_TO_DF								 ;AN000;
;											 ;AN000;
; Inputs:  AL = 7  Get truncate flag							 ;AN000;
;	   AL = 8  Set truncate flag							 ;AN000;
;		   DL = value								 ;AN000;
;	   AL = 9  Close all spool files						 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	IF AL=7 THEN DL = [TRUNCATE_FLAG]						 ;AN000;
;	ELSE DO 									 ;AN000;
;	       Get addr of 1st DFL entry.						 ;AN000;
;	       FOR I = 1 to last DFL entry in use					 ;AN000;
;		    Send request below to IFS specified if DFL. 			 ;AN000;
;	     ENDDO									 ;AN000;
;											 ;AN000;
;	Prep IFSRH:									 ;AN000;
;	*  IFSR_LENGTH	    DW	   48	    ; Request length				 ;AN000;
;	*  IFSR_FUNCTION    DB	    4	    ; Execute API function			 ;AN000;
;	   IFSR_RETCODE     DW	    ?							 ;AN000;
;	   IFSR_RETCLASS    DB	    ?							 ;AN000;
;	   IFSR_RESV1	    DB	   16 DUP(0)						 ;AN000;
;	*  IFSR_APIFUNC     DB	   16	    ; IFS dependent IOCTL			 ;AN000;
;	   IFSR_ERROR_CLASS DB	    ?							 ;AN000;
;	   IFSR_ERROR_ACTION DB     ?							 ;AN000;
;	   IFSR_ERROR_LOCUS DB	    ?							 ;AN000;
;	   IFSR_ALLOWED     DB	    ?							 ;AN000;
;	   IFSR_I24_RETRY   DB	    ?							 ;AN000;
;	   IFSR_I24_RESP    DB	    ?							 ;AN000;
;	   IFSR_RESV2	    DB	    ?							 ;AN000;
;	*  IFSR_DEVICE_CB@  DD	    ?	    ; DF					 ;AN000;
;	   IFSR_OPEN_CB@    DD	    ?							 ;AN000;
;	*  IFSR_FUNC	    DB	    0	    ;	00 Generic IOCTL by device number	 ;AN000;
;	   IFSR_RESV3	    DB	    0							 ;AN000;
;	*  IFSR_BUFFER@     DD	    ?							 ;AN000;
;	*  IFSR_BUFSIZE     DW	    1							 ;AN000;
;	   IFSR_CATEGORY    DB	    1 for UNC, 0 for other FSs				 ;AN000;
;	   IFSR_CTLFUNC     DB	    00000110 ; device_oper				 ;AN000;
;											 ;AN000;
;	   BUFFER	   LABEL   BYTE 						 ;AN000;
;			   DB	   function   ; 8 set truncate flag			 ;AN000;
;					      ; 9 close all spool files 		 ;AN000;
;			   DB	   truncate flag on set 				 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	Carry clear - DL = truncate flag on get 					 ;AN000;
;	Carry set   - AX = error code							 ;AN000;
;											 ;AN000;
; Regs: nothing preserved								 ;AN000;
;											 ;AN000;
; Notes: DFL not updated								 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure IFS_DEVICE_OPER,NEAR							 ;AN000;
											 ;AN000;
	CMP	AL,GET_TRUNCATE_FLAG							 ;AN000;
	JNE	IDO_20									 ;AN000;
	MOV	DL,[TRUNCATE_FLAG]		; Get truncate flag			 ;AN000;
	XOR	DH,DH									 ;AN015;
	CallInstall Get_User_Stack,multDOS,24						 ;AN015;
	MOV	[SI].User_DX,DX 							 ;AN015;
	transfer ifs_990			;  go ret no carry			 ;AN000;
											 ;AN000;
IDO_20: 					; Set truncate flag or close all	 ;AN000;
	ifsr_fcn_def	EXECAPI 		; spool files				 ;AN000;
	ifsr_api_def	DEPIOCTL							 ;AN000;
											 ;AN000;
	PUSH	CS				; get addressability to IFSSEG		 ;AN000;
	POP	DS									 ;AN000;
ASSUME	DS:IFSSEG,ES:NOTHING								 ;AN000;
											 ;AN000;
	MOV	DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@					 ;AN002;
	CMP	AL,SET_TRUNCATE_FLAG		; Set local storage of truncate_flag	 ;AN000;
	JNE	IDO_30									 ;AN000;
	MOV	[TRUNCATE_FLAG],DL							 ;AC002;
	MOV	AH,DL				; for safekeeping			 ;AN002;
											 ;AN000;
IDO_30: 										 ;AN000;
	MOV	CL,[DFLCount]			; Prep loop through DFL list		 ;AN000;
	OR	CL,CL				;   check for no dfl			 ;AN009;
	JNZ	IDO_35									 ;AN009;
	transfer ifs_990			;   no dfl - just go successfully	 ;AN009;
IDO_35:
	XOR	CH,CH									 ;AN000;
	MOV	DX,SIZE DFLL_LIST							 ;AN000;
	LDS	SI,[DFLAddr]								 ;AN000;
											 ;AN000;
IDO_40: 					; ** Loop here thru DFL list entries	 ;AN000;
;;;aliasCMP	DS:[SI.DFLL_TYPE],TYPE_ALIAS						 ;AN000;
;;;aliasJE	IDO_100 			; skip alias dfl entries		 ;AN000;
;;;alias										 ;AN000;
	TEST	DS:[SI.DFLL_FLAGS],DFL_INUSE	; skip unused dfl entries		 ;AN000;
	JZ	IDO_100 								 ;AN000;
	MOV	WORD PTR [THISDFL],SI		; Prep IFSRH				 ;AN000;
	MOV	WORD PTR [THISDFL+2],DS 						 ;AN000;
	invoke	PREP_IFSR								 ;AN000;
	invoke	DFL_TO_DF			; DFL: sets [THISIFS]			 ;AN000;
						;	    ES:BX -> IFSRH		 ;AN000;
						;	    IFSR_DEVICE_CB@		 ;AN000;
						;	    ds - IFSSEG 		 ;AN000;
	invoke	SET_DEPIOCTL_IFSR		; prep IFSRH				 ;AN000;
	MOV	SI,OFFSET TEMPBUF		; prep devoper buffer			 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],SI					 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],DS					 ;AN000;
	MOV	BYTE PTR DS:[SI],AL		; buffer contains: db fcn		 ;AN000;
	MOV	ES:[BX.IFSR_BUFSIZE],1							 ;AN002;
	CMP	AL,CLOSE_SPOOL_FILES		;		   db truncate flag	 ;AN000;
	JE	IDO_60									 ;AN000;
	MOV	BYTE PTR DS:[SI+1],AH							 ;AC002;
	INC	ES:[BX.IFSR_BUFSIZE]
IDO_60: 										 ;AN000;
	invoke	SET_CATEGORY								 ;AN000;
	MOV	ES:[BX.IFSR_CATEGORY],CL						 ;AN002;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_DEVOPER					 ;AN000;
											 ;AN000;
	SaveReg <CX>				; save count				 ;AN000;
	invoke	CALL_IFS			; call ifs with device oper request	 ;AN000;
	RestoreReg <CX> 			; restore count 			 ;AN000;
											 ;AN000;
IDO_100:										 ;AN000;
	ADD	SI,DX				; prep for next dfl			 ;AN000;
	LOOP	IDO_40				; go process next dfl			 ;AN000;
	transfer ifs_990			; Finished.  Go ret no carry.		 ;AN000;
											 ;AN000;
											 ;AN000;
EndProc IFS_DEVICE_OPER 								 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <IFS_SPOOL_ECHO_CHECK  See if FS controling LPT1 allows echo>			 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; IFS_SPOOL_ECHO_CHECK									 ;AN000;
;											 ;AN000;
;   Called by:	Dispatcher								 ;AN000;
;											 ;AN000;
;   Routines called: DFL_MATCH								 ;AN000;
;		     DFL_TO_DF								 ;AN000;
;		     CALL_IFS								 ;AN000;
; Inputs:  None 									 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	Call DFL_MATCH for match on "LPT1".                                              ;AN000;
;	IF match found THEN								 ;AN000;
;	   DO										 ;AN000;
;	     Prep IFSRH:								 ;AN000;
;	     *	IFSR_LENGTH	 DW	48	 ; Request length			 ;AN000;
;	     *	IFSR_FUNCTION	 DB	 4	 ; Execute API function 		 ;AN000;
;		IFSR_RETCODE	 DW	 ?						 ;AN000;
;		IFSR_RETCLASS	 DB	 ?						 ;AN000;
;		IFSR_RESV1	 DB	16 DUP(0)					 ;AN000;
;	     *	IFSR_APIFUNC	 DB	16	 ; IFS dependent IOCTL			 ;AN000;
;		IFSR_ERROR_CLASS DB	 ?						 ;AN000;
;		IFSR_ERROR_ACTION DB	 ?						 ;AN000;
;		IFSR_ERROR_LOCUS DB	 ?						 ;AN000;
;		IFSR_ALLOWED	 DB	 ?						 ;AN000;
;		IFSR_I24_RETRY	 DB	 ?						 ;AN000;
;		IFSR_I24_RESP	 DB	 ?						 ;AN000;
;		IFSR_RESV2	 DB	 ?						 ;AN000;
;	     *	IFSR_DEVICE_CB@  DD	 ?	 ; DF					 ;AN000;
;		IFSR_OPEN_CB@	 DD	 ?						 ;AN000;
;	     *	IFSR_FUNC	 DB	 0	 ; 00 Generic IOCTL by devnum		 ;AN000;
;		IFSR_RESV2	 DB	 0						 ;AN000;
;	     *	IFSR_BUFFER@	 DD	 ?						 ;AN000;
;	     *	IFSR_BUFSIZE	 DW	 ?						 ;AN000;
;		IFSR_CATEGORY	 DB	 ?	 ; 0 non-unc, 1 unc			 ;AN000;
;		IFSR_CTLFUNC	 DB	 00000011B					 ;AN000;
;											 ;AN000;
;		BUFFER	LABEL	BYTE							 ;AN000;
;			DB	VALUE,0 	; 0 echo allowed			 ;AN000;
;						; 1 echo not allowed			 ;AN000;
;											 ;AN000;
;											 ;AN000;
;	     Call routine, CALL_IFS, with DFL_IFSR_HDR					 ;AN000;
;	   ENDDO									 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	Carry clear - echo allowed							 ;AN000;
;	Carry set   - echo NOT allowed							 ;AN000;
;											 ;AN000;
;											 ;AN000;
; Regs: nothing preserved								 ;AN000;
;											 ;AN000;
; Programming notes:  DFL FSDA not updated						 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure IFS_SPOOL_ECHO_CHECK,NEAR						 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	ifsr_fcn_def	EXECAPI 							 ;AN000;
	ifsr_api_def	DEPIOCTL							 ;AN000;
											 ;AN000;
	SaveReg <ES,DI,DS,SI>			; save these for ibmdos (guessing which) ;AN011;
	MOV	CS:DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@	; make sure this positioned	 ;AN000;
							; right 			 ;AN000;
	PUSH	CS				; Set ds:si -> "lpt1",0                  ;AN000;
	POP	DS				; want to find dfl entry with		 ;AN000;
ASSUME	DS:IFSSEG				; this dev name 			 ;AN000;
	MOV	SI,OFFSET LPT1_NAME							 ;AN000;
											 ;AN000;
	invoke	DFL_MATCH								 ;AN000;
	JNC	ISEC_10 								 ;AN000;
	CLC					; not in dfl; assume echo ok		 ;AN011;
	JMP	ISEC_1000								 ;AC011;
											 ;AN000;
ISEC_10:										 ;AN000;
	LES	DI,[THISDFL]								 ;AN000;
;;;aliasCMP	ES:[DI.DFL_TYPE],TYPE_ALIAS						 ;AN000;
;;;aliasJNE	ISEC_15 								 ;AN000;
;;;aliastransfer ifs_980			; lpt1 is alias, assume no echo 	 ;AN000;
											 ;AN000;
ISEC_15:										 ;AN000;
	invoke	PREP_IFSR			; zero out ifsr 			 ;AN000;
	invoke	DFL_TO_DF			; DFL: sets [THISIFS]			 ;AN000;
						;	    ES:BX -> IFSRH		 ;AN000;
						;	    IFSR_DEVICE_CB@		 ;AN000;
						;	    ds - IFSSEG 		 ;AN000;
	invoke	SET_DEPIOCTL_IFSR		; prep IFSRH				 ;AN000;
	MOV	SI,OFFSET TEMPBUF							 ;AN000;
	MOV	WORD PTR ES:[BX.IFSR_BUFFER@],SI	; use tempbuf for		 ;AN000;
	MOV	WORD PTR ES:[BX.IFSR_BUFFER@+2],DS	; return byte value		 ;AN000;
	MOV	ES:[BX.IFSR_BUFSIZE],LENGTH_DEVECHOCHECK_BUFFER ; (1)			 ;AN000;
											 ;AN000;
	invoke	SET_CATEGORY								 ;AN000;
	MOV	ES:[BX.IFSR_CTLFUNC],CTLFUNC_DEVECHOCHECK  ; (00000011) 		 ;AN000;
											 ;AN000;
	invoke	CALL_IFS								 ;AN000;
											 ;AN000;
	JNC	ISEC_60 								 ;AN000;
	JMP	SHORT ISEC_1000 			; no echo on err, cf set	 ;AC011;
											 ;AN000;
ISEC_60:										 ;AN000;
	CMP	BYTE PTR DS:[SI],0			; else byte returned in buffr	 ;AN000;
	JE	ISEC_80 				; determines echo (0-yes,1-no)	 ;AN000;
	STC										 ;AN011;
	JMP	SHORT ISEC_1000 			; no echo ret			 ;AC011;
ISEC_80:										 ;AN000;
	CLC										 ;AN011;


ISEC_1000:						; echo ret			 ;AN011;
	RestoreReg <SI,DS,DI,ES>							 ;AN011;
	RET										 ;AN011;

											 ;AN000;
EndProc IFS_SPOOL_ECHO_CHECK								 ;AN000;
											 ;AN000;
BREAK <IFS_DEPENDENT_IOCTL  - dependent ioctl>						 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; IFS_DEPENDENT_IOCTL									 ;AN000;
;											 ;AN000;
; Called by:  Dispatcher								 ;AN000;
;											 ;AN000;
; Routines called:  CALL_IFS								 ;AN000;
;		    CDS_TO_CD	SFT_TO_SFF						 ;AN000;
;		    CD_TO_CDS	SFF_TO_SFT						 ;AN000;
;											 ;AN000;
; Inputs:										 ;AN000;
;	AL = 0 - Generic by device number						 ;AN000;
;	   BH = 0, BL = device number (0-def,1=a,2=b,...)  [THISCDS] set		 ;AN000;
;	   CX = private subfunction							 ;AN000;
;	   DS:DX -> buffer								 ;AN000;
;	AL = 1 - Generic by handle							 ;AN000;
;	   BX = handle	[THISSFT] set							 ;AN000;
;	   CX = private subfunction							 ;AN000;
;	   DS:DX -> buffer								 ;AN000;
;	AL = 2 - Query OS type								 ;AN000;
;	   BH = 0, BL = device number (0-def,1=a,2=b,...)  [THISCDS] set		 ;AN000;
;	   CX = buffer size								 ;AN000;
;	   ES:DI -> buffer								 ;AN000;
;											 ;AN000;
; Function:										 ;AN000;
;	Prep IFSRH:									 ;AN000;
;	*  IFSR_LENGTH	    DW	   48	    ; Request length				 ;AN000;
;	*  IFSR_FUNCTION    DB	    4	    ; Execute API function			 ;AN000;
;	   IFSR_RETCODE     DW	    ?							 ;AN000;
;	   IFSR_RETCLASS    DB	    ?							 ;AN000;
;	   IFSR_RESV1	    DB	   16 DUP(0)						 ;AN000;
;	*  IFSR_APIFUNC     DB	   16	    ; IFS dependent IOCTL			 ;AN000;
;	   IFSR_ERROR_CLASS DB	    ?							 ;AN000;
;	   IFSR_ERROR_ACTION DB     ?							 ;AN000;
;	   IFSR_ERROR_LOCUS DB	    ?							 ;AN000;
;	   IFSR_ALLOWED     DB	    ?							 ;AN000;
;	   IFSR_I24_RETRY   DB	    ?							 ;AN000;
;	   IFSR_I24_RESP    DB	    ?							 ;AN000;
;	   IFSR_RESV2	    DB	    ?							 ;AN000;
;	*  IFSR_DEVICE_CB@  DD	    ?	    ; Set by CDS_TO_CD (subfs 0,2)		 ;AN000;
;	*  IFSR_OPEN_CB@    DD	    ?	    ; Set by SFT_TO_SFF (subf 1)		 ;AN000;
;	*  IFSR_FUNC	    DB	    0	    ; AL - 0,1,or 2				 ;AN000;
;	   IFSR_RESV2	    DB	    0							 ;AN000;
;	*  IFSR_BUFFER@     DD	    ?	    ; al-2 es:di, else ds:dx			 ;AN000;
;	*  IFSR_BUFSIZE     DW	    ?	    ; al-2 cx, else ??? 			 ;AN000;
;;;; for al=0,1 									 ;AN000;
;	*  IFSR_CATEGORY    DB	    1	    ; 1 for UNC, 0 for non-UNC			 ;AN000;
;	*  IFSR_CTLFUNC     DB	    ?	    ; al-2 ???, else cx 			 ;AN000;
;											 ;AN000;
;											 ;AN000;
;	CALL routine, CALL_IFS, with pointer to IFS header				 ;AN000;
;	IF IFSR_RETCODE = 0 THEN							 ;AN000;
;	   DO										 ;AN000;
;	     IF CDS THEN								 ;AN000;
;		Call CD_TO_CDS								 ;AN000;
;	     ELSE Call SFF_TO_SFT							 ;AN000;
;	   ENDDO									 ;AN000;
;	ELSE										 ;AN000;
;	   Set carry									 ;AN000;
;	   Put error code in AX 							 ;AN000;
;	ENDIF										 ;AN000;
;											 ;AN000;
;   Outputs: function dependent 							 ;AN000;
;											 ;AN000;
;   Regs: nothing preserved								 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure IFS_DEPENDENT_IOCTL,NEAR						 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	ifsr_fcn_def	EXECAPI 							 ;AN000;
	ifsr_api_def	DEPIOCTL							 ;AN000;
											 ;AN000;
	MOV	CS:DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@	; make sure this positioned	 ;AN000;
							; right 			 ;AN000;
	SaveReg <BX,ES> 			; save input es for query os type	 ;AC006;
						; and bx for drive # / handle		 ;AN006;
											 ;AN000;
	MOV	CS:IFSPROC_FLAGS,ZERO		; init ifsfunc flags			 ;AN000;
	invoke	PREP_IFSR			;  & IFSR				 ;AN000;
											 ;AN000;
	invoke	SET_DEPIOCTL_IFSR		; prep IFSRH				 ;AN000;
	MOV	ES:[BX.IFSR_FUNC],AL		; 0,1, or 2				 ;AN000;
	CMP	AL,QUERY_OS_TYPE							 ;AN000;
	JE	IDI_10									 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],DX  ; ioctl generic			 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],DS					 ;AN000;
	MOV	ES:[BX.IFSR_CTLFUNC],CL 						 ;AN000;
	ADD	SP,2				; ditch es stored on stack		 ;AN000;
	JMP	SHORT IDI_15								 ;AN000;
IDI_10: 					; query os type 			 ;AN000;
	MOV	ES:[BX.IFSR_BUFSIZE],CX 	; cx is bufsize 			 ;AN000;
	POP	CX				; pop input es in cx			 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],DI					 ;AN000;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],CX					 ;AN000;
IDI_15: 										 ;AN000;
	CMP	AL,GEN_IOCTL_BY_HANDLE							 ;AN000;
	RestoreReg <CX> 			; restore input bx into ax, no cx	 ;AN006;;AC012;
						;	  (drive # or handle)		 ;AN006;
	JE	IDI_20									 ;AN000;
											 ;AN000;
;;;;;;; LDS	SI,[THISCDS]			; have device number (block only???)	 ;AD006;
						; Now get CDS:				 ;AN006;
	SaveReg <AX>				; function 0,1,2			 ;AN012;
	MOV	AX,CX				; input bx				 ;AN012;
	DEC	AL				; make 0-based				 ;AN006;
	MOV	CS:[IFSDRV],AL			; set this for possible i24		 ;AN006;
	CallInstall GetCDSFromDrv,multDOS,23,AX,AX					 ;AN006;
	RestoreReg <AX> 			; fcn 0,1,2				 ;AN012;
	JNC	IDI_17									 ;AN006;
IDI_16: 										 ;AN012;
	MOV	AX,error_invalid_drive		;   no cds, set error & ret		 ;AN006;
	JMP	IDI_120 			; ret up in FA to preserve DS		 ;AN006;
IDI_17: 					; (welcome lock)			 ;AN006;
	TEST	DS:[SI.curdir_flags],curdir_isifs	; check if drive ifs		 ;AN012;
	JZ	IDI_16
	SaveReg <DS,SI> 			; save cds ptr	al=0,2			 ;AN000;
	OR	IFSPROC_FLAGS,ISCDS							 ;AN000;
	invoke	CDS_TO_CD			; CDS: sets [THISIFS]			 ;AN000;
						;      IFSR_DEVICE_CB@			 ;AN000;
						;      ds - netwrk			 ;AN000;
	CMP	AL,QUERY_OS_TYPE							 ;AN000;
	JNE	IDI_40									 ;AN000;
	JMP	SHORT IDI_60								 ;AN000;
											 ;AN000;
IDI_20: 					; al=1					 ;AN000;
	Context DS									 ;AN000;
	OR	IFSPROC_FLAGS,SETDEVICECB						 ;AN000;
						; Now, need to get THISSFT set: 	 ;AN006;
	SaveReg <ES,DI,BX>			; these about to be clobbered		 ;AN006;
	MOV	BX,CX				; put handle in bx			 ;AC012;
	CallInstall pJFNFromHandle,multDOS,32	; intermediate step to getting sft	 ;AN006;
	JC	IDI_25									 ;AN006;
	CMP	BYTE PTR ES:[DI],-1		; unused handle 			 ;AN006;
	JE	IDI_25									 ;AN006;
	MOV	BL,BYTE PTR ES:[DI]		; get SFN				 ;AN006;
	XOR	BH,BH				; ignore upper half			 ;AN006;
	CallInstall SFFromSFN,multDOS,22	; get real sf spot			 ;AN006;
	MOV	WORD PTR [THISSFT],DI							 ;AN006;
	MOV	WORD PTR [THISSFT+2],ES 						 ;AN006;
	RestoreReg <BX,DI,ES>								 ;AN006;
	JMP	SHORT IDI_30								 ;AN006;
IDI_25: 					; sft error				 ;AN006;
	RestoreReg <BX,DI,ES>			; restore regs				 ;AN006;
	MOV	AX,error_invalid_handle 						 ;AN006;
	JMP	IDI_120 								 ;AN006;

IDI_30: 										 ;AN006;
	invoke	SFT_TO_SFF			; sets: [THISIFS]			 ;AN000;
						;	IFSR_OPEN_CB@			 ;AN000;
						;	ds - netwrk			 ;AN000;
IDI_40: 										 ;AN000;
	invoke	SET_CATEGORY			; set category 1-unc 0-other		 ;AN000;
	MOV	ES:[BX.IFSR_CATEGORY],CL						 ;AN000;
IDI_60:
	MOV	DX,IFSIOCTL			; check if fs supports fs ioctl
	invoke	CHECK_IFS_ATTRIBUTE
	JZ	IDI_80				; Z = no support, NZ = yes support
	JMP	DI_70				; continues in device_ioctl		 ;AN000;
											 ;AN000;
IDI_80: 					; error invalid fcn - fs doesn't support ;AN000;
	TEST	IFSPROC_FLAGS,ISCDS		; if cds, must clean stack of		 ;AN000;
	JZ	IDI_100 			; cds ptr				 ;AN000;
	ADD	SP,4									 ;AN000;
IDI_100:										 ;AN000;
	MOV	AX,error_invalid_function						 ;AN000;
IDI_120:										 ;AN006;
	invoke	SET_EXTERR_INFO 		; set error info			 ;AN006;
	transfer ifs_980			; go to general error return		 ;AN000;
											 ;AN000;
EndProc IFS_DEPENDENT_IOCTL								 ;AN000;


BREAK <DEVICE_IOCTL  - device ioctl>							 ;AN000;
											 ;AN000;
;******************************************************************************
;
; DEVICE_IOCTL
;
; Called by:  Dispatcher
;
; Routines called:  CALL_IFS
;		    CDS_TO_CD	SFT_TO_SFF
;		    CD_TO_CDS	SFF_TO_SFT
;
; Inputs:
;	AL = 02H(03H0 Read from(Write to) character device
;	   BX = handle	 [THISSFT] set
;	   CX = number of bytes to read(write)
;	   DS:DX -> buffer
;	AL = 0CH Character Generic IOCTL
;	   CH = 1-async, 3-display, 5-printer
;	   CL = 5F-set, 7F-get
;	   DS:DX -> buffer
;	AL = 0DH Block Generic IOCTL
;	   BH = 0
;	   BL = Drive number  [THISCDS] set (0-based)
;	   CH = 08
;	   CL = 43-set, 63-get media id
;	   DS:DX -> buffer
;
; Function:
;	Prep IFSRH:
;	*  IFSR_LENGTH	    DW	   48	    ; Request length
;	*  IFSR_FUNCTION    DB	    4	    ; Execute API function
;	   IFSR_RETCODE     DW	    ?
;	   IFSR_RETCLASS    DB	    ?
;	   IFSR_RESV1	    DB	   16 DUP(0)
;	*  IFSR_APIFUNC     DB	   17	    ; IFS device IOCTL
;	   IFSR_ERROR_CLASS DB	    ?
;	   IFSR_ERROR_ACTION DB     ?
;	   IFSR_ERROR_LOCUS DB	    ?
;	   IFSR_ALLOWED     DB	    ?
;	   IFSR_I24_RETRY   DB	    ?
;	   IFSR_I24_RESP    DB	    ?
;	   IFSR_RESV2	    DB	    ?
;	*  IFSR_DEVICE_CB@  DD	    ?	    ; Set by CDS_TO_CD (0DH)
;	*  IFSR_OPEN_CB@    DD	    ?	    ; Set by SFT_TO_SF (0CH)
;	*  IFSR_FUNC	    DB	    0	    ; AL 2,3,12,or 13
;	   IFSR_RESV2	    DB	    0
;	*  IFSR_BUFFER@     DD	    ?	    ; ds:dx
;	*  IFSR_BUFSIZE     DW	    ?	    ; cx for al=2,3
;	*  IFSR_CATEGORY    DB	    1	    ; ch for al=12,13
;	*  IFSR_CTLFUNC     DB	    ?	    ; cl for al=12,13
;
;
;	CALL routine, CALL_IFS
;	IF IFSR_RETCODE = 0 THEN
;	   DO
;	     IF CDS THEN
;		Call CD_TO_CDS
;	     ELSE Call SFF_TO_SFT
;	   ENDDO
;	ELSE
;	   Set carry
;	   Put error code in AX
;	ENDIF
;
;   Outputs: function dependent
;
;   Regs: nothing preserved
;
;******************************************************************************
											 ;AN000;
	procedure DEVICE_IOCTL,NEAR							 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
;	mov	ax,26				; these two instrs temporary
;	transfer ifs_980

	ifsr_fcn_def	EXECAPI 							 ;AN000;
	ifsr_api_def	DEVIOCTL							 ;AN000;
											 ;AN000;
	MOV	CS:DEVICE_CB@_OFFSET,IFSR_DEVICE_CB@	; make sure this positioned	 ;AN000;
							; right 			 ;AN000;
	PUSH	DS				; save input ds 			 ;AN000;
											 ;AN000;
	MOV	CS:IFSPROC_FLAGS,ZERO		; init processing flags 		 ;AN000;
	invoke	PREP_IFSR			;  & ifsr				 ;AN000;
	POP	ES:WORD PTR [BX.IFSR_BUFFER@+2] ; put input ds in now before clobber it  ;AN005;
											 ;AN000;
	CMP	AL,BLOCK_GENERIC							 ;AN000;
	JNE	DI_20									 ;AN000;
											 ;AN000;
	LDS	SI,[THISCDS]			; block generic - cds processing	 ;AN000;
	SaveReg <DS,SI> 			; save cds ptr				 ;AN000;
	OR	IFSPROC_FLAGS,ISCDS							 ;AN000;
	invoke	CDS_TO_CD			; CDS: sets [THISIFS]			 ;AN000;
						;      IFSR_DEVICE_CB@			 ;AN000;
						;      ds - netwrk			 ;AN000;
	JMP	SHORT DI_40								 ;AN000;
											 ;AN000;
DI_20:						; handle function			 ;AN000;
	OR	CS:IFSPROC_FLAGS,SetDeviceCB	; to get possible related cd or df	 ;AN000;
	Context DS									 ;AN000;
	invoke	SFT_TO_SFF			; sets: [THISIFS]			 ;AN000;
						;	IFSR_OPEN_CB@			 ;AN000;
						;	ds - netwrk			 ;AN000;
DI_40:											 ;AN000;
	MOV	ES:[BX.IFSR_LENGTH],LENGTH_DEVIOCTL					 ;AN000;
	MOV	ES:[BX.IFSR_FUNCTION],IFSEXECAPI					 ;AN000;
	MOV	ES:[BX.IFSR_APIFUNC],IFSDEVIOCTL					 ;AN000;
	MOV	ES:[BX.IFSR_FUNC],AL		; 2,3,12 or 13				 ;AN000;
;;;;;	POP	DS				; retrieve input ds			 ;AD005;
	MOV	ES:WORD PTR [BX.IFSR_BUFFER@],DX					 ;AN000;
;;;;;	MOV	ES:WORD PTR [BX.IFSR_BUFFER@+2],DS					 ;AD005;
	CMP	AL,CHAR_GENERIC 		; fork 2,3 vs 12,13			 ;AN000;
	JGE	DI_60				; go if 12,13
	MOV	ES:[BX.IFSR_BUFSIZE],CX 	; 2,3 processing
	JMP	SHORT DI_70
DI_60:						; 12,13 processing
	MOV	ES:[BX.IFSR_CATEGORY],CH	; 1,3,5,or 8
	MOV	ES:[BX.IFSR_CTLFUNC],CL 	; 5F,7F,4E,or 6E
											 ;AN000;
DI_70:											 ;AN000;
;-----------------------------------------------------------------------------------------
	invoke	CALL_IFS			; call ifs driver w/request		 ;AN000;
;-----------------------------------------------------------------------------------------
											 ;AN000;
	JNC	DI_100									 ;AN000;
	TEST	IFSPROC_FLAGS,ISCDS		; error return				 ;AN000;
	JNZ	DI_80				;   if cds clean up stack		 ;AN000;
	transfer ifs_1000			; go return in ifsutil			 ;AN000;
DI_80:											 ;AN000;
	ADD	SP,4				; restore stack 			 ;AN000;
	transfer ifs_980								 ;AN000;
											 ;AN000;
DI_100: 										 ;AN000;
	TEST	IFSPROC_FLAGS,ISCDS							 ;AN000;
	JNZ	DI_120									 ;AN000;
	MOV	AX,ES:[BX.IFSR_BUFSIZE] 	; set return size for 2,3 (won't hurt    ;AN000;
	invoke	SFF_TO_SFT			; for 12 either 			 ;AN000;
	transfer ifs_990								 ;AN000;
DI_120: 										 ;AN000;
	MOV	CX,ES:[BX.IFSR_BUFSIZE] 						 ;AN000;
	RestoreReg <DI,ES>			; restore cds ptr into esdi		 ;AN000;
	invoke	CD_TO_CDS								 ;AN000;
	transfer ifs_990								 ;AN000;
											 ;AN000;
											 ;AN000;
EndProc DEVICE_IOCTL									 ;AN000;
											 ;AN000;
											 ;AN000;
											 ;AN000;
BREAK <GET_DFL_FROM_INDEX  Get DFL entry from index>					 ;AN000;
											 ;AN000;
;****************************************************************************** 	 ;AN000;
;											 ;AN000;
; GET_DFL_FROM_INDEX									 ;AN000;
;											 ;AN000;
; Called by:  PRINTER_GETSET_STRING							 ;AN000;
;											 ;AN000;
; Routines called: none 								 ;AN000;
;											 ;AN000;
; Inputs:										 ;AN000;
;	BX is index number (as in GetIFSFUNCItem)					 ;AN000;
;											 ;AN000;
; Outputs:										 ;AN000;
;	Carry Clear									 ;AN000;
;		[THISDFL] set								 ;AN000;
;	Carry Set									 ;AN000;
;		Bad index number							 ;AN000;
;											 ;AN000;
; Regs: Preserves Printer Get/Set String input regs					 ;AN000;
;											 ;AN000;
;****************************************************************************** 	 ;AN000;
											 ;AN000;
	procedure GET_DFL_FROM_INDEX,NEAR						 ;AN000;
ASSUME	DS:NOTHING,ES:NOTHING								 ;AN000;
											 ;AN000;
	SaveReg <DS,SI,CX,DX>			; save Ptr GetSet Str input regs	 ;AC007;
						;     (removed ax from above)		 ;AN007;
	PUSH	BX									 ;AN000;
; Compute index # of first device							 ;AN000;
	XOR	BX,BX									 ;AN000;
	MOV	CX,BX									 ;AN000;
	Context DS				; DS-Dosgroup				 ;AN003;
	MOV	CL,[CDSCount]								 ;AN000;
	LDS	SI,[CDSAddr]			; Assume not paused			 ;AN000;
	CMP	CS:[fAssign],0								 ;AN000;
	JNZ	GDFI_20 								 ;AN000;
	LDS	SI,CS:[CDSAlt]			; Paused, get REAL CDSs from here	 ;AN000;
GDFI_20:										 ;AN000;
	TEST	[SI.CURDIR_FLAGS],CURDIR_ISIFS						 ;AN000;
	JZ	GDFI_40 								 ;AN000;
	INC	BX									 ;AN000;
;;;	TEST	[SI.CURDIR_TYPE],TYPE_NET_DRIVE 					 ;AD003;
;;;	JZ	GDFI_40 			; count 2 for redir			 ;AD003;
;;;	INC	BX									 ;AD003;
GDFI_40:										 ;AN000;
	ADD	SI,SIZE CURDIR_LIST		; Next CDS				 ;AN000;
	LOOP	GDFI_20 								 ;AN000;
						; BX is index # of first device 	 ;AN000;
	POP	AX				; Get user index #			 ;AN000;
	SUB	AX,BX									 ;AN000;
	JB	GDFI_60 			; if carry set (JB), user index <	 ;AN000;
						; 1st device index - too low		 ;AN000;
						; go return w/carry already set 	 ;AN000;
	MOV	CL,CS:[DFLCount]							 ;AN000;
	CMP	CL,AL				; AL is now device index #		 ;AN000;
	JAE	GDFI_80 								 ;AN000;
GDFI_60:										 ;AN000;
	MOV	AX,error_invalid_parameter	; user index too high			 ;AN000;
	JMP	GDFI_980			; go return w/carry already set 	 ;AN000;
GDFI_80:										 ;AN000;
	LDS	SI,CS:[DFLAddr] 							 ;AN000;
	MOV	BL,SIZE DFLL_list		; size in convenient spot		 ;AN000;
;;;	DEC	AX									 ;AD003
	MUL	BL				; get net offset			 ;AN000;
	ADD	SI,AX				; convert to true pointer		 ;AN000;
	TEST	DS:[SI.DFLL_FLAGS],dfl_inuse	; is this device attached?????		 ;AN014;
	JZ	GDFI_60 			; error if not
											 ;AN000;
	PUSH	DS									 ;AN000;
	POP	DX									 ;AN000;
	PUSH	CS									 ;AN000;
	POP	DS									 ;AN000;
ASSUME	DS:IFSSEG									 ;AN000;
	MOV	WORD PTR [THISDFL],SI							 ;AN000;
	MOV	WORD PTR [THISDFL+2],DX 						 ;AN000;
	invoke	PREP_IFSR			; init ifsr				 ;AN000;
	invoke	DFL_TO_DF								 ;AN000;
	JMP	GDFI_990								 ;AN000;
											 ;AN000;
											 ;AN000;
GDFI_980:					; Return area				 ;AN000;
	SaveReg <AX,CS> 			; set thisdfl null on error		 ;AN008;
	RestoreReg <DS> 								 ;AN008;
	MOV	AX,NULL_PTR								 ;AN008;
	MOV	WORD PTR [THISDFL],AX							 ;AN008;
	MOV	WORD PTR [THISDFL+2],AX 						 ;AN008;
	RestoreReg <AX> 								 ;AN008;
	STC										 ;AN000;
	JMP	GDFI_1000								 ;AN000;
GDFI_990:										 ;AN000;
	CLC										 ;AN000;
GDFI_1000:										 ;AN000;
	RestoreReg <DX,CX,SI,DS>		; restore regs				 ;AC007;
						;     (removed ax from above)		 ;AN007;
	return										 ;AN000;
											 ;AN000;
EndProc GET_DFL_FROM_INDEX								 ;AN000;
											 ;AN000;
											 ;AN000;
IFSSEG	ENDS										 ;AN000;
	END										 ;AN000;
